package com.qixiaobao.insure.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.qixiaobao.async.AsyncService;
import com.qixiaobao.common.config.SupplyConfig;
import com.qixiaobao.common.constant.CacheConstants;
import com.qixiaobao.common.core.domain.model.LoginUser;
import com.qixiaobao.common.core.rabbitmq.config.RabbitMqConfig;
import com.qixiaobao.common.core.rabbitmq.server.MsgSendServer;
import com.qixiaobao.common.core.redis.RedisCache;
import com.qixiaobao.common.exception.UtilException;
import com.qixiaobao.common.utils.MybatisBatchUtils;
import com.qixiaobao.common.utils.SecurityUtils;
import com.qixiaobao.common.utils.StringUtils;
import com.qixiaobao.common.utils.easyExcel.EasyExcelUtil;
import com.qixiaobao.common.utils.file.FileUtils;
import com.qixiaobao.common.utils.pdf.PdfWaterUtils;
import com.qixiaobao.common.utils.uuid.IdUtils;
import com.qixiaobao.insure.domain.*;
import com.qixiaobao.insure.domain.dto.*;
import com.qixiaobao.insure.mapper.InsureMapper;
import com.qixiaobao.insure.mapper.MatchInsureMapper;
import com.qixiaobao.insure.mapper.SchemeInsureMapper;
import com.qixiaobao.insure.mapper.SupplyInsureFileUploadLogMapper;
import com.qixiaobao.insure.service.IInsureService;
import com.qixiaobao.common.utils.oss.OssUtil;
import com.qixiaobao.nondirect.invoice.domain.domain.*;
import com.qixiaobao.system.domain.*;
import com.qixiaobao.system.domain.dto.PersonDTO;
import com.qixiaobao.system.mapper.*;
import com.qixiaobao.system.service.IFileInfoService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @Description 保单管理 服务层实现
 * @Author yangxm
 * @Date 2025/6/16 17:03
 */
@Slf4j
@Service
public class InsureServiceImpl implements IInsureService {


    @Autowired
    private InsureMapper insureMapper;
    @Autowired
    private DictMapper dictMapper;
    @Autowired
    private SupplyMapper supplyMapper;
    @Autowired
    private SlaveUserMapper slaveUserMapper;
    @Autowired
    private SchemeInsureMapper schemeInsureMapper;
    @Autowired
    private SignCompanyMapper signCompanyMapper;
    @Autowired
    private PersonMapper personMapper;
    @Autowired
    private MsgSendServer msgSendServer;
    @Autowired
    private MatchInsureMapper matchInsureMapper;
    @Autowired
    private AsyncService asyncService;
    @Autowired
    private FileInfoMapper fileInfoMapper;
    @Autowired
    private RedisCache redisCache;
    @Autowired
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;
    @Autowired
    private IFileInfoService fileInfoService;
    @Autowired
    private SupplyInsureFileUploadLogMapper supplyInsureFileUploadLogMapper;
    @Autowired
    private InsureLogMapper insureLogMapper;

    //手动事务
    @Resource
    private DataSourceTransactionManager transactionManager;
    @Autowired
    private TransactionDefinition transactionDefinition;


    private static final String ID_REG = "^\\d*$";
    private static final List<String> employerInsureperiodList = Arrays.asList("0", "1", "2", "3", "4", "6");

    /**
     * @param insureDTO
     * @return java.util.List<com.qixiaobao.insure.domain.Insure>
     * @Description 查询保单列表
     * @Author yangxm
     * @Date 2025/6/16 17:05
     */
    @Override
    public List<Insure> selectInsureList(InsureDTO insureDTO) {
        log.info("查询保单列表，参数：{}", insureDTO);
        long begin = System.currentTimeMillis();
        List<Insure> list = insureMapper.selectInsureList(insureDTO);
        log.info("查询保单列表，耗时：{}ms", System.currentTimeMillis() - begin);
        //字典值处理
        dictHandle(list);
        log.info("查询保单列表，总耗时：{}ms", System.currentTimeMillis() - begin);
        return list;
    }

    /**
     * @Description 导出保单列表
     * @Author yangxm
     * @Date 2025/6/17 14:11
     * @param insureDTO
     * @param response
     */
    @Override
    public void export(InsureDTO insureDTO, HttpServletResponse response) {
        log.info("导出保单列表开始--------------------");
        if (StringUtils.isBlank(insureDTO.getGurantStatus())){
            throw new IllegalArgumentException("缺少参数：保单状态");
        }
        String gurantStatus = insureDTO.getGurantStatus();
        String fileName;
        if (StringUtils.equals("7", gurantStatus)){
            fileName = "保单管理待生效";
        } else if (StringUtils.equals("8", gurantStatus)) {
            fileName = "保单管理在保中";
        } else if (StringUtils.equals("9", gurantStatus)) {
            fileName = "保单管理已失效";
        } else if (StringUtils.equals("10", gurantStatus)) {
            fileName = "保单管理退保已失效";
        } else {
            throw new IllegalArgumentException("参数：保单状态错误");
        }
        //封装表头
        List<String> arrayHeaders = new ArrayList<>();
        arrayHeaders.add("序号");
        arrayHeaders.add("方案Id");
        arrayHeaders.add("ID");
        arrayHeaders.add("订单编号");
        arrayHeaders.add("保单号");
        arrayHeaders.add("保单号状态");
        arrayHeaders.add("供应商全称");
        arrayHeaders.add("所属供应商");
        arrayHeaders.add("供应商简称");
        arrayHeaders.add("匹配后供应商简称");
        arrayHeaders.add("所属公司");
        arrayHeaders.add("被保人");
        arrayHeaders.add("付款单位");
        arrayHeaders.add("客户名称");
        arrayHeaders.add("套餐名称");
        arrayHeaders.add("伤残比例");
        arrayHeaders.add("扩展24小时");
        arrayHeaders.add("投保周期");
        arrayHeaders.add("投保方式");
        arrayHeaders.add("职业类别");
        arrayHeaders.add("猝死比例");
        arrayHeaders.add("保安猝死");
        arrayHeaders.add("匹配类型");
        arrayHeaders.add("生效起期");
        arrayHeaders.add("生效止期");
        arrayHeaders.add("保险费(元/人)");
        arrayHeaders.add("投保人数");
        arrayHeaders.add("客服");
        arrayHeaders.add("保险费总计");
        arrayHeaders.add("手续费率");
        arrayHeaders.add("备注");
        arrayHeaders.add("保单状态");
        arrayHeaders.add("凭证状态");
        arrayHeaders.add("凭证下载标识");
        arrayHeaders.add("推送时间");
        arrayHeaders.add("财务计入");
        arrayHeaders.add("保单结算状态");
        arrayHeaders.add("保单结算时间");
        if (!StringUtils.equals("10", gurantStatus)) {
            arrayHeaders.add("回单金额");
            arrayHeaders.add("回单编号");
            arrayHeaders.add("付款日期");
        }

        arrayHeaders.add("匹配时间");
        //动态表头
        List<List<String>> headList=new ArrayList<>();
        List<String> head=null;
        for (String strHead:arrayHeaders) {
            head=new ArrayList<>();
            head.add(strHead);
            headList.add(head);
        }
        //查询导出的数据
        List<Insure> list = selectInsureList(insureDTO);
        //动态表头的数据
        List<List<Object>> datalist=new ArrayList<>();
        List<Object> obj=null;
        Insure item;
        for (int i = 0; i < list.size(); i++) {
            item = list.get(i);
            obj = new ArrayList<>();
            obj.add(i + 1);
            obj.add(item.getCustomerMealId());
            obj.add(item.getId());
            obj.add(item.getQxbOrderNo());
            obj.add(item.getInsureNo());
            obj.add(item.getInsureNoStatus());
            obj.add(item.getSupplyName());
            obj.add(item.getBelongToSupply());
            obj.add(item.getSupplyShortName());
            obj.add(item.getToSupplyShortName());
            obj.add(item.getBelongCompanyName());
            obj.add(item.getInsurant());
            obj.add(item.getPayCompanyName());
            obj.add(item.getCustomerName());
            obj.add(item.getMealNameVal());
            obj.add(item.getMaimRatioVal());
            obj.add(item.getExtensionVal());
            obj.add(item.getInsurePeriodVal());
            obj.add(item.getInsureTypeVal());
            obj.add(item.getJobTypeVal());
            obj.add(item.getSuddenDeathRatioVal());
            obj.add(item.getGuardSuddenVal());
            obj.add(item.getMatchTypeVal());
            obj.add(Optional.ofNullable(item.getGurantBeginTime()).map(x-> DateFormatUtils.format(x, "yyyy/MM/dd HH:mm:ss")).orElse(""));
            obj.add(Optional.ofNullable(item.getGurantEndTime()).map(x-> DateFormatUtils.format(x, "yyyy/MM/dd HH:mm:ss")).orElse(""));
            obj.add(item.getCopeInsureFeePrice());
            obj.add(item.getAddNum());
            obj.add(item.getServiceName());
            obj.add(item.getCopeInsureFee());
            obj.add(item.getServiceRate());
            obj.add(item.getRemark());
            obj.add(item.getInsureFileStatus());
            obj.add(item.getCustomerInsDecStatus());
            obj.add(item.getTemplateDownloadFlag());
            obj.add(Optional.ofNullable(item.getPushTime()).map(x-> DateFormatUtils.format(x, "yyyy/MM/dd HH:mm:ss")).orElse(""));
            obj.add(item.getFinanceReckonVal());
            obj.add(item.getInsureFeeSettleVal());
            obj.add(Optional.ofNullable(item.getInsureFeeSettleTime()).map(x-> DateFormatUtils.format(x, "yyyy/MM/dd HH:mm:ss")).orElse(""));
            if (!StringUtils.equals("10", gurantStatus)) {
                obj.add(item.getTransAmount());
                obj.add(item.getBillNum());
                obj.add(Optional.ofNullable(item.getTransDateTime()).map(x-> DateFormatUtils.format(x, "yyyy/MM/dd")).orElse(""));
            }
            obj.add(Optional.ofNullable(item.getMatchTime()).map(x-> DateFormatUtils.format(x, "yyyy/MM/dd HH:mm:ss")).orElse(""));
            datalist.add(obj);
        }
        try {
            EasyExcelUtil.writeExcel(response, datalist, headList, fileName, fileName);
        } catch (IOException e) {
            log.error("{}导出异常：", fileName, e);
            throw new RuntimeException("导出失败：" + e.getMessage());
        }
    }

    /**
     * @Description 获取保单费用合计
     * @Author yangxm
     * @Date 2025/6/17 14:25
     * @param insureDTO
     * @return java.math.BigDecimal
     */
    @Override
    public BigDecimal copeInsureFeeTotal(InsureDTO insureDTO) {
        return insureMapper.selectCopeInsureFeeTotal(insureDTO);
    }

    /**
     * @Description 获取保单总人数
     * @Author yangxm
     * @Date 2025/6/17 14:25
     * @param insureDTO
     * @return java.lang.Integer
     */
    @Override
    public Integer insurePersonTotal(InsureDTO insureDTO) {
        return insureMapper.selectInsurePersonTotal(insureDTO);
    }

    /**
     * @Description 获取保单人员列表
     * @Author yangxm
     * @Date 2025/6/17 14:25
     * @param personDTO
     * @return java.util.List<com.qixiaobao.insure.domain.Person>
     */
    @Override
    public List<Person> personList(PersonDTO personDTO) {
        return personMapper.selectInsurePersonList(personDTO);
    }

    /**
     * @Description 一键下载银行回单，根据筛选条件下载，供应商简称必选
     * @Author yangxm
     * @Date 2025/6/18 10:02
     * @param insureDTO
     */
    @Override
    public void downloadReceipt(InsureDTO insureDTO) {
        LoginUser user = SecurityUtils.getLoginUser();
        if (user == null){
            throw new IllegalArgumentException("登陆超时，请重新登陆");
        }
        if (StringUtils.isEmpty(insureDTO.getSupplyIdList())){
            throw new IllegalArgumentException("缺少参数：供应商简称");
        }
        List<Long> supplyIdList = insureDTO.getSupplyIdList();
        if (StringUtils.isBlank(insureDTO.getGurantStatus())){
            throw new IllegalArgumentException("缺少参数：保单状态");
        }
        String gurantStatus = insureDTO.getGurantStatus();
        String operationType;
        if (StringUtils.equals("7", gurantStatus)){
            operationType = "保单管理待生效";
        } else if (StringUtils.equals("8", gurantStatus)) {
            operationType = "保单管理在保中";
        } else if (StringUtils.equals("9", gurantStatus)) {
            operationType = "保单管理已失效";
        } else {
            throw new IllegalArgumentException("参数：保单状态错误");
        }
        log.info("一键下载银行回单，操作人：{}, 操作页面：{}, 参数：{}", user.getUsername(), operationType, insureDTO);
        String supplyShortNames;
        List<String> supplyShortNameList = supplyMapper.selectShortNameByIdList(supplyIdList);
        if (StringUtils.isEmpty(supplyShortNameList)){
            log.error("一键下载银行回单异常，未查到供应商简称，操作人：{}, 操作页面：{}, 参数：{}", user.getUsername(), operationType, insureDTO);
            throw new IllegalArgumentException("未查到供应商简称");
        }
        supplyShortNames = StringUtils.join(supplyShortNameList, ",");
        //查询需要下载的银行回单ID集合
        List<Long> idList = insureMapper.selectPaymentProofIdList(insureDTO);
        log.info("一键下载银行回单，操作人：{}, 操作页面：{}, 银行回单ID集合：{}", user.getUsername(), operationType, idList);
        if (StringUtils.isNotEmpty(idList)){
            //将信息放入mq
            JSONObject message = new JSONObject();
            message.put("userId", user.getId());
            message.put("client", "supply");
            message.put("ids", idList);
            message.put("supplyShortName", supplyShortNames);
            message.put("operationType", operationType);
            msgSendServer.sendDirectByRoute(RabbitMqConfig.DIRECT_EXCHANGE, RabbitMqConfig.PAYMENT_ROUTING_KEY, message.toJSONString(), new CorrelationData(IdUtils.simpleUUID()));
        }
    }

    /**
     * @Description 根据上传的文件，删除保单号
     * @Author yangxm
     * @Date 2025/6/18 10:45
     * @param insureNoTempDtoList
     * @return java.lang.String
     */
    @Override
    public String removeInsureNoByTemp(List<InsureNoRemoveTempDTO> insureNoTempDtoList) {
        LoginUser user = SecurityUtils.getLoginUser();
        if (user == null) {
            throw new IllegalArgumentException("登陆失效，请重新登陆！");
        }
        int successNum = 0;
        int failureNum = 0;
        StringBuilder successMsg = new StringBuilder();
        StringBuilder failureMsg = new StringBuilder();
        List<String> updateList = new ArrayList<>();
        Insure insure;
        InsureLog insureLog;
        List<String> qxbOrderNoList;
        List<InsureLog> insureLogList = new ArrayList<>();
        //开启事务：手动提交/回滚事务
        TransactionStatus transactionStatus = transactionManager.getTransaction(transactionDefinition);
        try {
            //去重
            qxbOrderNoList = insureNoTempDtoList.stream().map(InsureNoRemoveTempDTO::getQxbOrderNo).collect(Collectors.toList());
            if (StringUtils.isEmpty(qxbOrderNoList)){
                throw new IllegalArgumentException("文件订单编号不能为空，请检查！");
            }
            qxbOrderNoList = qxbOrderNoList.stream().distinct().collect(Collectors.toList());
            //循环
            for (int i = 0; i < qxbOrderNoList.size(); i++) {
                String qxbOrderNo = qxbOrderNoList.get(i);
                if (StringUtils.isBlank(qxbOrderNo)) {
                    failureNum++;
                    String msg = "<br/>" + "第 " + (i + 2) + "行，缺少订单编号。";
                    failureMsg.append(msg);
                    continue;
                } else {
                    //校验订单编号是否存在
                    insure = insureMapper.checkIsExistByQxbOrderNo(qxbOrderNo);
                    if (insure == null) {
                        failureNum++;
                        String msg = "<br/>" + "第 " + (i + 2) + " 行，订单编号不存在！";
                        failureMsg.append(msg);
                        continue;
                    }
                }
                //需要删除的保单号对应的订单编号集合
                updateList.add(qxbOrderNo);
                //封装操作记录
                insureLog = new InsureLog();
                insureLog.setInsureId(insure.getId());
                insureLog.setClient("2");
                insureLog.setOperateType("3");
                insureLog.setContent("保单号：" + insure.getInsureNo() + " 删除");
                insureLog.setCreateBy(user.getUsername());
                insureLogList.add(insureLog);
            }
            //批量删除保单号
            if (StringUtils.isNotEmpty(updateList)) {
                insureMapper.updateInsureNoByQxbOrderNoList(updateList);
            }
            //批量保存操作记录
            if (StringUtils.isNotEmpty(insureLogList)) {
                MybatisBatchUtils.batchUpdateOrInsert(insureLogList, InsureLogMapper.class, InsureLogMapper::insertInsureLog);
            }
            //手动提交事务
            transactionManager.commit(transactionStatus);
        }catch (Exception e){
            //手动回滚事务
            transactionManager.rollback(transactionStatus);
            log.error("根据文件匹配删除保单号异常：{}", e);
            throw new RuntimeException("操作失败：" + e.getMessage());
        }
        //根据订单编号（匹配后），查询匹配前的在保或已失效的保单ID
        if (StringUtils.isNotEmpty(updateList)){
            //雇主保
            MatchInsure matchInsure = new MatchInsure();
            matchInsure.setToQxbOrderNoList(updateList);
            List<Long> fromInsureIdList = matchInsureMapper.selectFromInsureIdList(matchInsure);
            //匹配前投保数据处理
            if (StringUtils.isNotEmpty(fromInsureIdList)){
                asyncService.matchInsureHandle(fromInsureIdList, false, false);
            }
            //天保
            SchemeInsure schemeInsure = new SchemeInsure();
            schemeInsure.setToQxbOrderNoList(updateList);
            //根据匹配后的保单ID，查询匹配前的在保或已失效的投保数据
            fromInsureIdList = schemeInsureMapper.selectFromInsureIdList(schemeInsure);
            //匹配前投保数据处理
            if (StringUtils.isNotEmpty(fromInsureIdList)){
                asyncService.matchInsureHandle(fromInsureIdList, false, true);
            }
        }
        for (int i = 0; i < updateList.size(); i++) {
            successNum++;
            successMsg.append("<br/>" + successNum + "、 订单编号：" + updateList.get(i) + "，删除保单号成功");
        }
        if (failureNum > 0) {
            failureMsg.insert(0, "很抱歉，删除失败！共 " + failureNum + " 条数据格式不正确，错误如下：");
            throw new RuntimeException(failureMsg.toString());
        } else {
            successMsg.insert(0, "恭喜您，数据已全部删除成功！共 " + successNum + " 条，数据如下：");
        }
        return successMsg.toString();
    }

    /**
     * @Description 根据上传的文件，删除保单文件
     * @Author yangxm
     * @Date 2025/6/18 14:45
     * @param insureNoTempDtoList
     * @return java.lang.String
     */
    @Override
    public String removeInsureFileByTemp(List<InsureNoRemoveTempDTO> insureNoTempDtoList) {
        LoginUser user = SecurityUtils.getLoginUser();
        if (user == null) {
            throw new IllegalArgumentException("登陆失效，请重新登陆！");
        }
        int successNum = 0;
        int failureNum = 0;
        StringBuilder successMsg = new StringBuilder();
        StringBuilder failureMsg = new StringBuilder();
        List<String> updateList = new ArrayList<>();
        Insure insure;
        InsureLog insureLog;
        List<String> qxbOrderNoList;
        String qxbOrderNo;
        List<InsureLog> insureLogList = new ArrayList<>();
        //开启事务：手动提交/回滚事务
        TransactionStatus transactionStatus = transactionManager.getTransaction(transactionDefinition);
        try {
            //去重
            qxbOrderNoList = insureNoTempDtoList.stream().map(InsureNoRemoveTempDTO::getQxbOrderNo).collect(Collectors.toList());
            if (StringUtils.isEmpty(qxbOrderNoList)){
                throw new IllegalArgumentException("文件订单编号不能为空，请检查！");
            }
            qxbOrderNoList = qxbOrderNoList.stream().distinct().collect(Collectors.toList());
            //循环
            for (int i = 0; i < qxbOrderNoList.size(); i++) {
                qxbOrderNo = qxbOrderNoList.get(i);
                if (StringUtils.isBlank(qxbOrderNo)) {
                    failureNum++;
                    String msg = "<br/>" + "第 " + (i + 2) + "行，缺少订单编号。";
                    failureMsg.append(msg);
                    continue;
                } else {
                    //校验订单编号是否存在
                    insure = insureMapper.checkIsExistByQxbOrderNo(qxbOrderNo);
                    if (insure == null) {
                        failureNum++;
                        String msg = "<br/>" + "第 " + (i + 2) + " 行，订单编号不存在！";
                        failureMsg.append(msg);
                        continue;
                    }
                }
                //需要删除的保单文件对应的订单编号集合
                updateList.add(qxbOrderNo);
                //封装操作记录
                insureLog = new InsureLog();
                insureLog.setInsureId(insure.getId());
                insureLog.setClient("2");
                insureLog.setOperateType("4");
                insureLog.setContent("保单文件：" + insure.getInsureNo() + " 删除");
                insureLog.setCreateBy(user.getUsername());
                insureLogList.add(insureLog);
            }
            //批量删除保单文件和保单凭证合并文件
            if (StringUtils.isNotEmpty(updateList)) {
                //批量删除保单文件
                insureMapper.updateInsureFileByQxbOrderNoList(updateList);
                //批量删除保单凭证合并文件
                insureMapper.deleteInsureFileProofMergeUrlByQxbOrderNoList(updateList);
            }
            //批量保存操作记录
            if (StringUtils.isNotEmpty(insureLogList)) {
                MybatisBatchUtils.batchUpdateOrInsert(insureLogList, InsureLogMapper.class, InsureLogMapper::insertInsureLog);
            }
            //手动提交事务
            transactionManager.commit(transactionStatus);
        }catch (Exception e){
            //手动回滚事务
            transactionManager.rollback(transactionStatus);
            log.error("根据文件匹配删除保单号异常：{}", e);
            throw new RuntimeException("操作失败：" + e.getMessage());
        }
        //根据订单编号（匹配后），查询匹配前的在保或已失效的保单ID
        if (StringUtils.isNotEmpty(updateList)){
            //雇主保
            MatchInsure matchInsure = new MatchInsure();
            matchInsure.setToQxbOrderNoList(updateList);
            List<Long> fromInsureIdList = matchInsureMapper.selectFromInsureIdList(matchInsure);
            //匹配前投保数据处理
            if (StringUtils.isNotEmpty(fromInsureIdList)){
                asyncService.matchInsureHandle(fromInsureIdList, false, false);
            }
            //天保
            SchemeInsure schemeInsure = new SchemeInsure();
            schemeInsure.setToQxbOrderNoList(updateList);
            //根据匹配后的保单ID，查询匹配前的在保或已失效的投保数据
            fromInsureIdList = schemeInsureMapper.selectFromInsureIdList(schemeInsure);
            //匹配前投保数据处理
            if (StringUtils.isNotEmpty(fromInsureIdList)){
                asyncService.matchInsureHandle(fromInsureIdList, false, true);
            }
        }
        for (int i = 0; i < updateList.size(); i++) {
            successNum++;
            successMsg.append("<br/>" + successNum + "、 订单编号：" + updateList.get(i) + "，删除保单文件成功");
        }
        if (failureNum > 0) {
            failureMsg.insert(0, "很抱歉，删除失败！共 " + failureNum + " 条数据格式不正确，错误如下：");
            throw new RuntimeException(failureMsg.toString());
        } else {
            successMsg.insert(0, "恭喜您，数据已全部删除成功！共 " + successNum + " 条，数据如下：");
        }
        return successMsg.toString();
    }

    /**
     * @Description 解析保单号文件
     * @Author yangxm
     * @Date 2025/6/18 15:43
     * @param fileInfoId
     * @param noPermissionSupplyIdList  没有权限操作的供应商id集合
     * @return java.lang.String
     */
    @Override
    public String analysisInsureNoFile(String fileInfoId, List<Long> noPermissionSupplyIdList) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (loginUser == null){
            throw new UtilException("登录超时，请重新登陆");
        }
        // 校验文件
        FileInfo fileInfo = fileInfoMapper.selectFileInfoById(fileInfoId);
        if (fileInfo == null) {
            throw new UtilException("文件不存在，请重新上传!");
        }
        String filePath = fileInfo.getPath();
        if (StringUtils.isBlank(filePath)) {
            throw new UtilException("文件路径不存在，请重新上传!");
        }
        filePath = filePath.trim();
        //读取文件
        List<Map<Integer, String>> list = EasyExcelUtil.read(filePath);
        if (list.size() < 2){
            throw new UtilException("文件内容不能为空，请检查！");
        }
        //错误信息
        StringBuilder errorMsg;
        String errorMsgStr;
        boolean hasError = false;

        long insureId;
        Insure insure = null;
        InsureNoImportTempDTO insureNoImportTempDTO;
        List<InsureNoImportTempDTO> insureNoImportTempDTOList = new ArrayList<>();
        //需要更新的保单
        Insure updateInsure;
        List<Insure> updateInsureList = new ArrayList<>();

        String rowStr;
        //整行数据是否重复
        Map<String, Integer> existsRow = new HashMap<>();
        //保单id是否重复
        Map<String, Integer> existsInsureId = new HashMap<>();
        //订单编号是否重复
        Map<String, Integer> existsQxbOrderNo = new HashMap<>();

        //每行的Map<列索引, 值>
        Map<Integer, String> map;
        for (int i = 0; i < list.size(); i++) {
            map = list.get(i);
            if (i == 0){
                if (map.size() < 4){
                    throw new UtilException("不是最新模板，请使用最新模板");
                }
                if (StringUtils.isBlank(map.get(0)) || StringUtils.isBlank(map.get(1))
                        || StringUtils.isBlank(map.get(2)) || StringUtils.isBlank(map.get(3))
                        || StringUtils.equals("序号", map.get(0)) || StringUtils.equals("ID号", map.get(1))
                        || StringUtils.equals("订单编号", map.get(2)) || StringUtils.equals("保单号", map.get(3))){
                    throw new UtilException("模板错误，请检查！");
                }
            } else {
                errorMsg = new StringBuilder();
                insureNoImportTempDTO = new InsureNoImportTempDTO();
                insureNoImportTempDTO.setIndexNo(map.get(0));
                insureNoImportTempDTO.setInsureId(map.get(1));
                insureNoImportTempDTO.setQxbOrderNo(map.get(2));
                insureNoImportTempDTO.setInsureNo(map.get(3));
                if (StringUtils.isBlank(map.get(0))){
                    errorMsg.append(String.format("第 %d 行序号不能为空", i+1));
                }
                if (StringUtils.isBlank(map.get(1))){
                    errorMsg.append(String.format("第 %d 行ID号不能为空", i+1));
                }
                if (StringUtils.isBlank(map.get(2))){
                    errorMsg.append(String.format("第 %d 行订单编号不能为空", i+1));
                }
                if (StringUtils.isBlank(map.get(3))){
                    errorMsg.append(String.format("第 %d 行保单号不能为空", i+1));
                }
                //校验订单编号和ID号
                if (StringUtils.equals("0", insureNoImportTempDTO.getInsureId()) && StringUtils.equals("0", insureNoImportTempDTO.getQxbOrderNo())) {
                    errorMsg.append(String.format("第 %d 行ID号和订单编号不能同时为0", i+1));
                } else if (!StringUtils.equals("0", insureNoImportTempDTO.getInsureId()) && !StringUtils.equals("0", insureNoImportTempDTO.getQxbOrderNo())) {
                    errorMsg.append(String.format("第 %d 行ID号和订单编号不能同时不为0", i+1));
                } else {
                    if (!Pattern.matches(ID_REG, insureNoImportTempDTO.getInsureId())) {
                        errorMsg.append(String.format("第 %d 行ID号格式有误", i+1));
                    }
                    if (!StringUtils.equals("0", insureNoImportTempDTO.getInsureId())){
                        insureId = Long.parseLong(insureNoImportTempDTO.getInsureId());
                        insure = insureMapper.selectInsureById(insureId);
                        if (insure == null) {
                            errorMsg.append(String.format("第 %d 行ID号不存在", i+1));
                        } else {
                            if (StringUtils.isNotBlank(insure.getInsureNo())) {
                                errorMsg.append(String.format("第 %d 行保单号已存在", i+1));
                            } else {
                                if (StringUtils.isNotEmpty(noPermissionSupplyIdList)){
                                    if (noPermissionSupplyIdList.contains(insure.getSupplyId())){
                                        errorMsg.append(String.format("第 %d 行ID号无权限操作", i+1));
                                    }
                                }
                            }
                        }
                    }
                    if (!StringUtils.equals("0", insureNoImportTempDTO.getQxbOrderNo())){
                        insure = insureMapper.selectInsureByQxbOrderNo(insureNoImportTempDTO.getQxbOrderNo());
                        if (insure == null) {
                            errorMsg.append(String.format("第 %d 行订单编号不存在", i+1));
                        } else {
                            if (StringUtils.isNotBlank(insure.getInsureNo())) {
                                errorMsg.append(String.format("第 %d 行保单号已存在", i+1));
                            } else {
                                if (StringUtils.isNotEmpty(noPermissionSupplyIdList)){
                                    if (noPermissionSupplyIdList.contains(insure.getSupplyId())){
                                        errorMsg.append(String.format("第 %d 行ID号无权限操作", i+1));
                                    }
                                }
                            }
                        }
                    }
                }
                rowStr = String.format("%s:%s:%s", insureNoImportTempDTO.getInsureId(), insureNoImportTempDTO.getQxbOrderNo(), insureNoImportTempDTO.getInsureNo());
                if (existsRow.containsKey(rowStr)) {
                    errorMsg.append(String.format("第 %d 行与 第 %d 行重复", i+1, existsRow.get(rowStr)));
                }else {
                    existsRow.put(rowStr, i+1);
                    if (!StringUtils.equals("0", insureNoImportTempDTO.getInsureId())){
                        if (existsInsureId.containsKey(insureNoImportTempDTO.getInsureId())) {
                            errorMsg.append(String.format("第 %d 行与 第 %d 行ID号重复", i+1, existsInsureId.get(insureNoImportTempDTO.getInsureId())));
                        } else {
                            existsInsureId.put(insureNoImportTempDTO.getInsureId(), i+1);
                        }
                    }
                    if (!StringUtils.equals("0", insureNoImportTempDTO.getQxbOrderNo())){
                        if (existsQxbOrderNo.containsKey(insureNoImportTempDTO.getQxbOrderNo())) {
                            errorMsg.append(String.format("第 %d 行与 第 %d 行订单编号重复", i+1, existsQxbOrderNo.get(insureNoImportTempDTO.getQxbOrderNo())));
                        } else {
                            existsQxbOrderNo.put(insureNoImportTempDTO.getQxbOrderNo(), i+1);
                        }
                    }
                }
                //错误信息封装
                errorMsgStr = errorMsg.toString();
                if (StringUtils.isNotBlank(errorMsgStr)){
                    if (!hasError){
                        hasError = true;
                    }
                    insureNoImportTempDTO.setErrorMsg(errorMsgStr);
                    insureNoImportTempDTOList.add(insureNoImportTempDTO);
                }else {
                    //没有错误，则保存要更新的保单信息
                    updateInsure = new Insure();
                    if (insure != null){
                        updateInsure.setId(insure.getId());
                    }
                    updateInsure.setInsureNo(insureNoImportTempDTO.getInsureNo());
                    updateInsureList.add(updateInsure);
                }

            }
        }
        //若错误标识为true，则生成错误的excel
        String fileUrl = "";
        if (hasError) {
            updateInsureList.clear();
            String errorFilePath = SupplyConfig.getProfile() + "/" + FileUtils.getPath() + IdUtils.fastSimpleUUID() + ".xlsx";
            try {
                EasyExcelUtil.writeExcel(new FileOutputStream(errorFilePath), insureNoImportTempDTOList, InsureNoImportTempDTO.class, "sheet1");
                //上传到oss
                OssUtil.ins().uploadFile(errorFilePath, new FileInputStream(errorFilePath));
                //获取url
                fileUrl = OssUtil.ins().getFileUrl(filePath);
            } catch (FileNotFoundException e) {
                log.error("导入保单号，解析保单号文件异常：", e);
                throw new UtilException("系统异常：" + e.getMessage());
            }finally {
                //删除文件
                FileUtils.deleteFile(errorFilePath);
            }
        }else {
            String redisKey = CacheConstants.INSURE_NO_IMPORT_KEY + loginUser.getId();
            //判断key是否存在
            if (redisCache.hasKey(redisKey)){
                //删除key
                redisCache.deleteObject(redisKey);
            }
            redisCache.setCacheList(redisKey, updateInsureList);
            redisCache.expire(redisKey, 60);
        }
        return fileUrl;
    }

    /**
     * @Description 导入保单号
     * @Author yangxm
     * @Date 2025/6/19 13:09
     * @param fileInfoId
     * @param noPermissionSupplyIdList
     * @return int
     */
    @Override
    public int uploadInsureNo(String fileInfoId, List<Long> noPermissionSupplyIdList) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (loginUser == null){
            throw new UtilException("登录超时，请重新登陆");
        }
        List<Insure> insureList;
        //判断解析结果是否存在
        String redisKey = CacheConstants.INSURE_NO_IMPORT_KEY + loginUser.getId();
        //判断key是否存在，若不存在，则重新解析
        if (!redisCache.hasKey(redisKey)){
            String fileUrl = analysisInsureNoFile(fileInfoId, noPermissionSupplyIdList);
            if (StringUtils.isNotBlank(fileUrl)){
                throw new UtilException("文件中包含错误信息，请重新上传文件");
            }
        }
        insureList = redisCache.getCacheList(redisKey);
        if (StringUtils.isEmpty(insureList)){
            throw new UtilException("解析文件内容失败！");
        }

        Insure insure;
        InsureLog insureLog;
        List<InsureLog> insureLogList = new ArrayList<>();
        for (int i = 0; i < insureList.size(); i++) {
            insure = insureList.get(i);
            //操作记录封装
            //操作记录封装
            insureLog = new InsureLog();
            insureLog.setInsureId(insure.getId());
            insureLog.setClient("2");
            insureLog.setOperateType("2");
            insureLog.setContent("保单号上传：" + insure.getInsureNo());
            insureLog.setCreateBy(loginUser.getUsername());
            insureLogList.add(insureLog);
        }

        //批量更新保单号
        MybatisBatchUtils.batchUpdateOrInsert(insureList, InsureMapper.class, InsureMapper::updateInsureNoById);
        //批量保存操作记录
        MybatisBatchUtils.batchUpdateOrInsert(insureLogList, InsureLogMapper.class, InsureLogMapper::insertInsureLog);
        return 1;
    }

    /**
     * @Description 定向下载模板  解析模板内容
     * @Author yangxm
     * @Date 2025/6/19 14:33
     * @param insureQxbOrderNoTempDTOList
     * @return java.lang.String
     */
    @Override
    public InsureQxbOrderNoTempDTO analysisQxbOrderNoFile(List<InsureQxbOrderNoTempDTO> insureQxbOrderNoTempDTOList) {

        int failureNum = 0;
        StringBuilder failureMsg = new StringBuilder();

        //模板中供应商简称集合(去重)
        List<String> supplyShortNameList = insureQxbOrderNoTempDTOList.stream().map(InsureQxbOrderNoTempDTO::getSupplyShortName).filter(StringUtils::isNotBlank).distinct().collect(Collectors.toList());
        //订单编号集合（未去重）
        List<String> allQxbOrderNoList = insureQxbOrderNoTempDTOList.stream().map(InsureQxbOrderNoTempDTO::getQxbOrderNo).filter(StringUtils::isNotBlank).collect(Collectors.toList());
        //订单编号集合（去重）
        List<String> qxbOrderNoList = insureQxbOrderNoTempDTOList.stream().map(InsureQxbOrderNoTempDTO::getQxbOrderNo).filter(StringUtils::isNotBlank).distinct().collect(Collectors.toList());
        //获取重复的订单编号集合
        allQxbOrderNoList.removeAll(qxbOrderNoList);
        if (StringUtils.isNotEmpty(allQxbOrderNoList)) {
            throw new UtilException("存在重复的订单编号：" + allQxbOrderNoList);
        }
        List<Insure> insures = insureMapper.selectInsureByQxbOrderNoList(qxbOrderNoList);
        //根据订单编号集合查询保单信息
        Map<String, Insure> insureMap = insures.stream().collect(Collectors.toMap(Insure::getQxbOrderNo, s -> s));

        String qxbOrderNo;
        Insure insure;
        for (int i = 0; i < insureQxbOrderNoTempDTOList.size(); i++) {
            qxbOrderNo = insureQxbOrderNoTempDTOList.get(i).getQxbOrderNo();
            if (StringUtils.isNotBlank(qxbOrderNo)) {
                //根据订单号获取保单信息
                insure = insureMap.get(qxbOrderNo);
                if (insure == null) {
                    log.error("【InsureServiceImpl】[analysisQxbOrderNoFile] 保单信息不存在：{}", qxbOrderNo);
                    failureNum++;
                    String msg = "<br/>" + "订单编号： " + qxbOrderNo + "，对应的保单信息不存在！";
                    failureMsg.append(msg);
                    continue;
                }
                if (!employerInsureperiodList.contains(insure.getInsurePeriod())) {
                    log.error("【InsureServiceImpl】[analysisQxbOrderNoFile] 不能生成非雇主保保单模板：{}", qxbOrderNo);
                    failureNum++;
                    String msg = "<br/>" + "订单编号： " + qxbOrderNo + "，不能生成非雇主保保单模板！";
                    failureMsg.append(msg);
                    continue;
                }
                if (StringUtils.isBlank(insure.getInsureNo())) {
                    log.error("【InsureServiceImpl】[analysisQxbOrderNoFile] 未上传保单号：{}", qxbOrderNo);
                    failureNum++;
                    String msg = "<br/>" + "订单编号： " + qxbOrderNo + "，未上传保单号！";
                    failureMsg.append(msg);
                    continue;
                }
                if (!insure.getSupplyShortName().equals(insureQxbOrderNoTempDTOList.get(i).getSupplyShortName())) {
                    log.error("【InsureServiceImpl】[analysisQxbOrderNoFile] 供应商简称错误：{}", qxbOrderNo);
                    failureNum++;
                    String msg = "<br/>" + "订单编号： " + qxbOrderNo + "，对应的供应商简称错误！";
                    failureMsg.append(msg);
                }
            }
        }
        if (failureNum > 0) {
            failureMsg.insert(0, "很抱歉，校验失败！共 " + failureNum + " 条数据格式不正确，错误如下：");
            throw new UtilException(failureMsg.toString());
        }
        InsureQxbOrderNoTempDTO result = new InsureQxbOrderNoTempDTO();
        result.setInsureIdList(insures.stream().map(Insure::getId).collect(Collectors.toList()));
        result.setSupplyShortName(StringUtils.join(supplyShortNameList, ","));
        return result;
    }

    /**
     * @Description 生成凭证文件
     * @Author yangxm
     * @Date 2025/6/19 15:16
     * @param insureIdList
     * @param supplyShortName
     */
    @Override
    public void generateCustomerInsDec(List<Long> insureIdList, String supplyShortName) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        //将信息放入redis消息队列，topic为generateInsureProofFile
        JSONObject message = new JSONObject();
        message.put("userId", loginUser.getId());
        message.put("client", "supply");
        message.put("ids", insureIdList);
        message.put("supplyShortName", supplyShortName);
        message.put("generateFlag", "0");
        msgSendServer.sendDirectByRoute(RabbitMqConfig.DIRECT_EXCHANGE, RabbitMqConfig.PROOF_ROUTING_KEY, message.toJSONString(), new CorrelationData(IdUtils.simpleUUID()));
    }

    /**
     * @Description 导入保单文件  校验保单文件名称
     * @Author yangxm
     * @Date 2025/6/19 16:02
     * @param fileNames  文件名字可以是订单编号也可以是保单号
     */
    @Override
    public Map<String, List<String>> checkUploadInsureFile(List<String> fileNames) {
        log.info("[InsureServiceImpl] [checkUploadInsureFile] 开始校验保单文件名称: {}", fileNames);
        //文件名称处理
        List<String> fileNameList = fileNames.stream()
                .map(name -> name.contains(".") ? name.substring(0, name.lastIndexOf(".")) : name)
                .map(String::trim)
                .distinct()
                .collect(Collectors.toList());
        //返回结果
        Map<String, List<String>> result = new HashMap<String, List<String>>();

        //查找订单编号存在的集合，返回值为订单编号
        List<String> existentialQxbOrderNos = insureMapper.checkByQxbOrderNoList(fileNameList);
        //假如文件名为保单号，检查保单号是否存在 yangxm  禅道：2485
        List<String> insureNos = insureMapper.checkByInsureNoList(fileNameList);
        if ((existentialQxbOrderNos == null || existentialQxbOrderNos.isEmpty()) && (insureNos == null || insureNos.isEmpty())) {
            result.put("nonExistent", fileNameList);
            return result;
        }

        List<String> qxbOrderNoSuccessList = new ArrayList<>();
        //查找保单文件为null的保单信息，返回值为订单编号
        if (existentialQxbOrderNos != null && !existentialQxbOrderNos.isEmpty()) {
            qxbOrderNoSuccessList = insureMapper.checkSuccessInsureFileByQxbOrderNoList(existentialQxbOrderNos);
        }
        List<String> insureNoSuccessList = new ArrayList<>();
        //查找保单文件为null的保单信息，返回值为保单号
        if (insureNos != null && !insureNos.isEmpty()) {
            insureNoSuccessList = insureMapper.checkSuccessInsureFileByInsureNoList(insureNos);
        }

        //返回不存在的订单编号
        List<String> nonExistentList = ListUtils.removeAll(fileNameList, existentialQxbOrderNos);
        //返回不存在的保单号
        List<String> insureNoExistentList = ListUtils.removeAll(nonExistentList, insureNos);

        //返回已存在保单文件的订单号
        List<String> repeatList = ListUtils.removeAll(existentialQxbOrderNos, qxbOrderNoSuccessList);
        //返回已存在保单文件的保单号
        List<String> insureNoRepeatList = ListUtils.removeAll(insureNos, insureNoSuccessList);

        result.put("nonExistent", insureNoExistentList);
        result.put("success", ListUtils.union(qxbOrderNoSuccessList, insureNoSuccessList));
        result.put("repeat", ListUtils.union(repeatList, insureNoRepeatList));
        log.info("[InsureServiceImpl] [checkUploadInsureFile] 结束校验保单文件名称，结果： {}", result);
        return result;
    }

    /**
     * @Description 上传保单文件
     * @Author yangxm
     * @Date 2025/6/16 17:05
     * @param files
     * @param checkFlag
     * @param coverFlag
     */
    @Override
    public String uploadInsureFile(MultipartFile[] files, String checkFlag, String coverFlag) {
        long begin = System.currentTimeMillis();
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (loginUser == null) {
            throw new UtilException("登陆失效，请重新登陆！");
        }
        if (files.length == 0){
            throw new UtilException("文件不能为空！");
        }
        log.info("InsureServiceImpl [uploadInsureFiles] 供应商保单批量上传----------，文件数量：{}", files.length);
        List<Long> ids = new ArrayList<>();
        int successNum = 0;
        int failureNum = 0;
        StringBuilder successMsg = new StringBuilder();
        StringBuilder failureMsg = new StringBuilder();
        //每一个任务的list
        List<FutureTask<HashMap<String,Object>>> taskList = new ArrayList<>();
        //将文件上传到oss，并保存到t_supply_file_upload_log表中
        for (MultipartFile file : files){
            FutureTask<HashMap<String,Object>> task = new FutureTask<>(new SaveSupplyInsureFileUploadLogJob(file, loginUser.getUsername()));
            threadPoolTaskExecutor.execute(task);
            taskList.add(task);
        }
        for (FutureTask<HashMap<String, Object>> item : taskList) {
            try {
                if (Integer.valueOf(item.get().get("code").toString()) == 500) {
                    failureNum++;
                    failureMsg.append(item.get().get("msg"));
                } else {
                    successNum++;
                    successMsg.append(item.get().get("msg"));
                    ids.add(Long.valueOf(item.get().get("id").toString()));
                }
            } catch (InterruptedException | ExecutionException e) {
                throw new RuntimeException(e);
            }
        }
        if (StringUtils.isNotBlank(failureMsg)) {
            failureMsg.insert(0, "很抱歉，上传失败！共 " + failureNum + " 条数据校验未通过，错误如下：");
            throw new UtilException(failureMsg.toString());
        } else {
            log.info("InsureServiceImpl [uploadInsureFiles] 供应商保单批量上传，发送mq文件数量：{}", ids.size());
            //将信息放入mq消息队列
            JSONObject message = new JSONObject();
            message.put("userId", loginUser.getId());
            message.put("client", "supply");
            message.put("ids", ids);
            message.put("checkFlag", checkFlag);
            message.put("coverFlag", coverFlag);
            msgSendServer.sendDirectByRoute(RabbitMqConfig.DIRECT_EXCHANGE, RabbitMqConfig.INSURE_FILE_UPLOAD_ROUTING_KEY, message.toJSONString(), new CorrelationData(IdUtils.simpleUUID()));
            successMsg.insert(0, "恭喜您，数据已全部上传成功！共 " + successNum + " 条，数据如下：");
        }
        log.info("InsureServiceImpl [uploadInsureFiles] 供应商保单批量上传完成，耗时：{}", (System.currentTimeMillis() - begin));
        return successMsg.toString();
    }

    /**
     * @Description 保单号维护
     * @Author yangxm
     * @Date 2025/6/19 16:56
     * @param supplyInsureInfo
     * @return int
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int operationInsureNo(SupplyInsureInfo supplyInsureInfo) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (loginUser == null) {
            throw new UtilException("获取登录信息失败");
        }
        //更新保单号
        int row = insureMapper.updateInsureNoBatch(supplyInsureInfo);
        //更新增减员费用的保单号
        insureMapper.updateAdminusCharge(supplyInsureInfo);
        //更新保单费用的保单号
        insureMapper.updateInsureCharge(supplyInsureInfo);
        //更新供应商设置的保单号
        SupplyInsureInfo info = insureMapper.getSupplyInsureno(supplyInsureInfo.getSupplyId(), supplyInsureInfo.getDateInfo());
        if (info != null) {
            info.setInsureNo(supplyInsureInfo.getInsureNo());
            insureMapper.updateSupplyInsureNo(info);
        } else {
            insureMapper.saveSupplyInsureNo(supplyInsureInfo);
        }
        //操作记录封装
        List<Insure> insureList = insureMapper.selectSupplyInsureNoList(supplyInsureInfo);
        if (StringUtils.isNotEmpty(insureList)) {
            Insure insure;
            InsureLog insureLog;
            List<InsureLog> insureLogList = new ArrayList<>();
            for (int i = 0; i < insureList.size(); i++) {
                insure = insureList.get(i);
                insureLog = new InsureLog();
                insureLog.setInsureId(insure.getId());
                insureLog.setClient("2");
                insureLog.setOperateType("3");
                insureLog.setContent("保单号维护，变更前：" + insure.getInsureNo() + ", 变更后：" + supplyInsureInfo.getInsureNo());
                insureLog.setCreateBy(loginUser.getUsername());
                insureLogList.add(insureLog);
            }
            if (StringUtils.isNotEmpty(insureLogList)) {
                MybatisBatchUtils.batchUpdateOrInsert(insureLogList, InsureLogMapper.class, InsureLogMapper::insertInsureLog);
            }
        }
        return row;
    }

    /**
     * @Description 导入凭证文件   校验凭证文件名称
     * @Author yangxm
     * @Date 2025/6/20 9:35
     * @param fileNames
     * @return java.util.Map<java.lang.String,java.util.List<java.lang.String>>
     */
    @Override
    public Map<String, List<String>> checkUploadCustomerInsDecFile(List<String> fileNames) {
        log.info("InsureServiceImpl [checkUploadCustomerInsDecFile] 开始校验凭证文件名称，文件：{}", fileNames);
        //文件名称处理
        List<String> fileNameList = fileNames.stream()
                .map(name -> name.contains(".") ? name.substring(0, name.lastIndexOf(".")) : name)
                .map(String::trim)
                .distinct()
                .collect(Collectors.toList());
        //返回结果
        Map<String, List<String>> result = new HashMap<String, List<String>>();

        //查找订单编号存在的集合，返回值为订单编号
        List<String> existentialQxbOrderNos = insureMapper.checkByQxbOrderNoList(fileNameList);

        if (existentialQxbOrderNos == null || existentialQxbOrderNos.isEmpty()) {
            result.put("nonExistent", fileNameList);
            return result;
        }

        //查找凭证文件不为null的保单信息，返回值为订单编号
        List<String> successList = insureMapper.checkSuccessCustomerInsDecFileByQxbOrderNoList(existentialQxbOrderNos);

        List<String> nonExistentList = ListUtils.removeAll(fileNameList, existentialQxbOrderNos);
        List<String> repeatList = ListUtils.removeAll(existentialQxbOrderNos, successList);

        result.put("nonExistent", nonExistentList);//未找到
        result.put("success", successList);//成功
        result.put("repeat", repeatList);//重复
        log.info("InsureServiceImpl [checkUploadCustomerInsDecFile] 结束校验凭证文件名称，结果：{}", result);
        return result;
    }

    /**
     * @Description 导入凭证文件
     * @Author yangxm
     * @Date 2025/6/20 9:58
     * @param files
     * @return java.lang.String
     */
    @Override
    public String uploadCustomerInsDecFile(MultipartFile[] files) {
        long begin = System.currentTimeMillis();
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (loginUser == null) {
            throw new UtilException("登陆失效，请重新登陆！");
        }
        if (files.length == 0){
            throw new UtilException("文件不能为空！");
        }
        log.info("InsureServiceImpl [uploadCustomerInsDecFile] 供应商凭证批量上传----------，文件数量：{}", files.length);
        int successNum = 0;
        int failureNum = 0;
        StringBuilder successMsg = new StringBuilder();
        StringBuilder failureMsg = new StringBuilder();
        //每一个任务的list
        List<FutureTask<HashMap<String,Object>>> taskList = new ArrayList<>();
        //异步执行任务
        for (MultipartFile file : files){
            FutureTask<HashMap<String,Object>> task = new FutureTask<>(new SaveCustomerInsDecFileUploadJob(file, loginUser.getUsername()));
            threadPoolTaskExecutor.execute(task);
            taskList.add(task);
        }
        for (FutureTask<HashMap<String, Object>> item : taskList) {
            try {
                if (Integer.valueOf(item.get().get("code").toString()) == 500) {
                    failureNum++;
                    failureMsg.append(item.get().get("msg"));
                } else {
                    successNum++;
                    successMsg.append(item.get().get("msg"));
                }
            } catch (InterruptedException | ExecutionException e) {
                log.error("InsureServiceImpl [uploadCustomerInsDecFile] 异步任务执行异常", e);
                throw new UtilException(e.getMessage());
            }
        }
        if (StringUtils.isNotBlank(failureMsg)) {
            failureMsg.insert(0, "很抱歉，上传失败！共 " + failureNum + " 条数据校验未通过，错误如下：");
            throw new UtilException(failureMsg.toString());
        }
        log.info("InsureServiceImpl [uploadCustomerInsDecFile] 供应商凭证批量上传完成，耗时：{}", (System.currentTimeMillis() - begin));
        return successMsg.toString();
    }

    /**
     * @Description 凭证下载
     * @Author yangxm
     * @Date 2025/6/20 14:40
     * @param insureDTO
     */
    @Override
    public void downloadCustomerInsDecFile(InsureDTO insureDTO) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (loginUser == null) {
            throw new UtilException("登陆失效，请重新登陆！");
        }
        Supply supply = supplyMapper.selectSupplyById(insureDTO.getSupplyIdList().get(0));
        if (supply == null){
            throw new UtilException("供应商不存在！");
        }
        String supplyShortName = supply.getMatchSupplyShortName();
        List<Long> ids;
        if (StringUtils.isNotEmpty(insureDTO.getInsureIdList())) {
            ids = insureDTO.getInsureIdList();
        } else {
            ids = insureMapper.selectIdList(insureDTO);
        }
        //将信息放入redis消息队列，topic为generateInsureProofFile
        JSONObject message = new JSONObject();
        message.put("userId", loginUser.getId());
        message.put("client", "supply");
        message.put("ids", ids);
        message.put("supplyShortName", supplyShortName);
        message.put("generateFlag", "0");
        CorrelationData correlationData = new CorrelationData(IdUtils.simpleUUID());
        msgSendServer.sendDirectByRoute(RabbitMqConfig.DIRECT_EXCHANGE, RabbitMqConfig.PROOF_ROUTING_KEY, message.toJSONString(), correlationData);
    }

    /**
     * @Description 删除所有文件
     * @Author yangxm
     * @Date 2025/6/20 15:14
     * @param insureDTO
     * @return int
     */
    @Override
    public int removeAllFile(InsureDTO insureDTO) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (loginUser == null) {
            throw new UtilException("登陆失效，请重新登陆！");
        }
        List<Long> ids;
        if (StringUtils.isNotEmpty(insureDTO.getInsureIdList())) {
            ids = insureDTO.getInsureIdList();
        } else {
            if (StringUtils.isEmpty(insureDTO.getSupplyIdList())) {
                throw new UtilException("参数：供应商简称不能为空");
            }
            ids = insureMapper.selectIdList(insureDTO);
        }
        if (StringUtils.isEmpty(ids)) {
            throw new UtilException("未查询到数据");
        }
        log.info("凭证/保单文件/供应商保单文件批量删除，ids:{}", ids);
        List<InsureLog> insureLogList = new ArrayList<>();
        //开启事务，手动提交/回滚事务
        TransactionStatus transactionStatus = transactionManager.getTransaction(transactionDefinition);
        //根据保单id查询该保单的保单文件、供应商保单文件、凭证
        List<Insure> insureList = insureMapper.selectInsureFileByIdList(ids);
        int row = 0;
        try {
            if (StringUtils.isNotEmpty(insureList)) {
                Insure insure;
                InsureLog insureLog;
                for (int i = 0; i < insureList.size(); i++) {
                    insure = insureList.get(i);
                    //保单文件
                    if (StringUtils.isNotBlank(insure.getInsureFile())) {
                        insureLog = new InsureLog();
                        insureLog.setInsureId(insure.getId());
                        insureLog.setClient("2");
                        insureLog.setOperateType("4");
                        insureLog.setContent("保单删除");
                        insureLog.setFileUrlBefore(StringUtils.join(fileInfoMapper.getFileUrlListByOwner(insure.getInsureFile()), ";"));
                        insureLog.setCreateBy(loginUser.getUsername());
                        insureLogList.add(insureLog);
                    }
                    //供应商保单文件
                    if (StringUtils.isNotBlank(insure.getSupplierInsureFile())) {
                        insureLog = new InsureLog();
                        insureLog.setInsureId(insure.getId());
                        insureLog.setClient("2");
                        insureLog.setOperateType("4");
                        insureLog.setContent("供应商保单删除");
                        insureLog.setFileUrlBefore(StringUtils.join(fileInfoMapper.getFileUrlListByOwner(insure.getSupplierInsureFile()), ";"));
                        insureLog.setCreateBy(loginUser.getUsername());
                        insureLogList.add(insureLog);
                    }
                    //客户凭证
                    if (StringUtils.isNotBlank(insure.getCustomerInsDec())) {
                        insureLog = new InsureLog();
                        insureLog.setInsureId(insure.getId());
                        insureLog.setClient("2");
                        insureLog.setOperateType("5");
                        insureLog.setContent("凭证删除");
                        insureLog.setFileUrlBefore(StringUtils.join(fileInfoMapper.getFileUrlListByOwner(insure.getCustomerInsDec()), ";"));
                        insureLog.setCreateBy(loginUser.getUsername());
                        insureLogList.add(insureLog);
                    }
                }
            }
            //批量保存操作记录
            if (StringUtils.isNotEmpty(insureLogList)) {
                MybatisBatchUtils.batchUpdateOrInsert(insureLogList, InsureLogMapper.class, InsureLogMapper::insertInsureLog);
            }
            //更新保单文件
            row = MybatisBatchUtils.batchUpdateOrInsert(ids, InsureMapper.class, InsureMapper::removeAllFile);
            //删除保单凭证合并文件
            if (StringUtils.isNotEmpty(ids)){
                log.info("凭证/保单文件/供应商保单文件批量删除，删除已经同步的保单凭证合并文件，保单ids：{}", ids);
                insureMapper.deleteInsureFileProofMergeUrlByIds(ids);
            }
            //手动提交事务
            transactionManager.commit(transactionStatus);
        }catch (Exception e){
            //手动回滚事务
            transactionManager.rollback(transactionStatus);
            log.error("凭证/保单文件/供应商保单文件批量删除异常，ids：{}，异常信息：", ids, e);
            throw new RuntimeException("操作失败：" + e.getMessage());
        }
        //根据保单ID（匹配后），查询匹配前的在保或已失效的保单ID
        if (StringUtils.isNotEmpty(ids)){
            MatchInsure matchInsure = new MatchInsure();
            matchInsure.setToInsureIdList(ids);
            //雇主保
            List<Long> fromInsureIdList = matchInsureMapper.selectFromInsureIdList(matchInsure);
            //匹配前投保数据处理
            if (StringUtils.isNotEmpty(fromInsureIdList)){
                asyncService.matchInsureHandle(fromInsureIdList, false, false);
            }
            //天保
            SchemeInsure schemeInsure = new SchemeInsure();
            schemeInsure.setToInsureIdList(ids);
            //根据匹配后的保单ID，查询匹配前的在保或已失效的投保数据
            fromInsureIdList = schemeInsureMapper.selectFromInsureIdList(schemeInsure);
            //匹配前投保数据处理
            if (StringUtils.isNotEmpty(fromInsureIdList)){
                asyncService.matchInsureHandle(fromInsureIdList, false, true);
            }
        }
        return row;
    }

    /**
     * @Description 一键生成凭证
     * @Author yangxm
     * @Date 2025/6/20 15:38
     * @param insureDTO
     */
    @Override
    public void generateCustomerInsDecFile(InsureDTO insureDTO) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (loginUser == null) {
            throw new UtilException("登陆失效，请重新登陆！");
        }
        List<Long> ids;
        if (StringUtils.isNotEmpty(insureDTO.getInsureIdList())) {
            ids = insureDTO.getInsureIdList();
        } else {
            ids = insureMapper.selectIdList(insureDTO);
        }
        if (StringUtils.isEmpty(ids)) {
            throw new UtilException("未查询到匹配的保单数据！");
        }

        List<Insure> insureList = insureMapper.selectInsureListByIdList(ids);
        if (StringUtils.isEmpty(insureList)){
            throw new UtilException("未查询到保单数据！");
        }
        //保单Map(k:保单id，v:保单信息)
        Map<Long, Insure> insureMap = insureList.stream().collect(Collectors.toMap(Insure::getId, insure -> insure));

        List<Long> messageList = new ArrayList<Long>();
        //保单id
        Long insureId;
        //保单实体
        Insure insure;
        //供应商简称集合
        List<String> supplyShortNameList = new ArrayList<>();
        //数据循环处理
        for (int i = 0; i < ids.size(); i++) {
            insureId = ids.get(i);
            insure = insureMap.get(insureId);
            if (StringUtils.isNull(insure)){
                log.info("一键生成凭证，保单信息不存在，保单ID：{}", insureId);
                continue;
            }
            if (StringUtils.isBlank(insure.getQxbOrderNo())){
                log.info("一键生成凭证，订单编号不存在，保单ID：{}", insureId);
                continue;
            }
            if(StringUtils.isBlank(insure.getInsureNo())) {
                if(insure.getSupplyId().compareTo(29L)!=0){
                    log.info("一键生成凭证，保单号为空，保单ID：{}", insureId);
                    continue;
                }
            }
            if (StringUtils.isBlank(insure.getSupplyShortName())){
                log.info("一键生成凭证，供应商简称不存在，保单ID：{}", insureId);
                continue;
            }

            if(StringUtils.isNull(insure.getSupplyTemplateId())) {
                log.info("一键生成凭证，凭证模板不存在，保单ID：{}", insureId);
                continue;
            }

            if(!employerInsureperiodList.contains(insure.getInsurePeriod())) {
                log.info("一键生成凭证，投保周期错误，保单ID：{}", insureId);
                continue;
            }
            if (!supplyShortNameList.contains(insure.getSupplyShortName())){
                supplyShortNameList.add(insure.getSupplyShortName());
            }
            messageList.add(insureId);
        }

        log.info("【InsureServiceImpl】[generateCustomerInsDecFile]一键生成凭证，保单id:{}", messageList);
        if(!messageList.isEmpty()) {
            //将信息放入redis消息队列，topic为generateInsureProofFile
            JSONObject message = new JSONObject();
            message.put("userId", loginUser.getId());
            message.put("client", "supply");
            message.put("ids", messageList);
            message.put("supplyShortName", StringUtils.join(supplyShortNameList, ","));
            message.put("generateFlag", "1");
            CorrelationData correlationData = new CorrelationData(IdUtils.simpleUUID());
            msgSendServer.sendDirectByRoute(RabbitMqConfig.DIRECT_EXCHANGE, RabbitMqConfig.PROOF_ROUTING_KEY, message.toJSONString(), correlationData);
        }else {
            throw new IllegalArgumentException("未匹配到待下载文件");
        }
    }

    /**
     * @Description 保单存档列表
     * @Author yangxm
     * @Date 2025/7/2 11:24
     * @param insureDTO
     * @return java.util.List<com.qixiaobao.insure.domain.Insure>
     */
    @Override
    public List<Insure> selectFullList(InsureDTO insureDTO) {
        insureDTO.setInsureFullFlag("1");
        long begin = System.currentTimeMillis();
        log.info("查询全量保单信息---------------");
        List<Insure> insureList = insureMapper.selectInsureList(insureDTO);
        log.info("查询全量保单信息,sql耗时：{}", System.currentTimeMillis() - begin);
        dictHandle(insureList);
        return insureList;
    }

    /**
     * @Description 保单存档列表导出
     * @Author yangxm
     * @Date 2025/7/2 11:45
     * @param insureDTO
     * @param response
     */
    @Override
    public void fullExport(InsureDTO insureDTO, HttpServletResponse response) {
        //封装表头
        List<String> arrayHeaders = new ArrayList<>();
        arrayHeaders.add("序号");
        arrayHeaders.add("ID");
        arrayHeaders.add("订单编号");
        arrayHeaders.add("保单号");
        arrayHeaders.add("保单号状态");
        arrayHeaders.add("供应商全称");
        arrayHeaders.add("所属供应商");
        arrayHeaders.add("供应商简称");
        arrayHeaders.add("匹配后供应商简称");
        arrayHeaders.add("所属公司");
        arrayHeaders.add("被保人");
        arrayHeaders.add("付款单位");
        arrayHeaders.add("客户名称");
        arrayHeaders.add("套餐名称");
        arrayHeaders.add("伤残比例");
        arrayHeaders.add("扩展24小时");
        arrayHeaders.add("投保周期");
        arrayHeaders.add("投保方式");
        arrayHeaders.add("职业类别");
        arrayHeaders.add("猝死比例");
        arrayHeaders.add("保安猝死");
        arrayHeaders.add("匹配属性");
        arrayHeaders.add("生效起期");
        arrayHeaders.add("生效止期");
        arrayHeaders.add("保险费(元/人)");
        arrayHeaders.add("投保人数");
        arrayHeaders.add("客服");
        arrayHeaders.add("保险费总计");
        arrayHeaders.add("手续费率");
        arrayHeaders.add("备注");
        arrayHeaders.add("保单状态");
        arrayHeaders.add("推送时间");
        arrayHeaders.add("保单结算状态");
        arrayHeaders.add("保单结算时间");
        arrayHeaders.add("回单金额");
        arrayHeaders.add("回单编号");
        arrayHeaders.add("付款日期");
        arrayHeaders.add("匹配时间");
        //动态表头
        List<List<String>> headList=new ArrayList<>();
        List<String> head=null;
        for (String strHead:arrayHeaders) {
            head=new ArrayList<>();
            head.add(strHead);
            headList.add(head);
        }
        //查询导出的数据
        List<Insure> list = selectFullList(insureDTO);
        //动态表头的数据
        List<List<Object>> datalist=new ArrayList<>();
        List<Object> obj=null;
        Insure item;
        for (int i = 0; i < list.size(); i++) {
            item = list.get(i);
            obj = new ArrayList<>();
            obj.add(i + 1);
            obj.add(item.getId());
            obj.add(item.getQxbOrderNo());
            obj.add(item.getInsureNo());
            obj.add(item.getInsureNoStatus());
            obj.add(item.getSupplyName());
            obj.add(item.getBelongToSupply());
            obj.add(item.getSupplyShortName());
            obj.add(item.getToSupplyShortName());
            obj.add(item.getBelongCompanyName());
            obj.add(item.getInsurant());
            obj.add(item.getPayCompanyName());
            obj.add(item.getCustomerName());
            obj.add(item.getMealNameVal());
            obj.add(item.getMaimRatioVal());
            obj.add(item.getExtensionVal());
            obj.add(item.getInsurePeriodVal());
            obj.add(item.getInsureTypeVal());
            obj.add(item.getJobTypeVal());
            obj.add(item.getSuddenDeathRatioVal());
            obj.add(item.getGuardSuddenVal());
            obj.add(item.getMatchTypeVal());
            obj.add(Optional.ofNullable(item.getGurantBeginTime()).map(x-> DateFormatUtils.format(x, "yyyy/MM/dd HH:mm:ss")).orElse(""));
            obj.add(Optional.ofNullable(item.getGurantEndTime()).map(x-> DateFormatUtils.format(x, "yyyy/MM/dd HH:mm:ss")).orElse(""));
            obj.add(item.getCopeInsureFeePrice());
            obj.add(item.getAddNum());
            obj.add(item.getServiceName());
            obj.add(item.getCopeInsureFee());
            obj.add(item.getServiceRate());
            obj.add(item.getRemark());
            obj.add(item.getOriginalInsureFileStatus());
            obj.add(Optional.ofNullable(item.getPushTime()).map(x-> DateFormatUtils.format(x, "yyyy/MM/dd HH:mm:ss")).orElse(""));
            obj.add(item.getInsureFeeSettle());
            obj.add(Optional.ofNullable(item.getInsureFeeSettleTime()).map(x-> DateFormatUtils.format(x, "yyyy/MM/dd HH:mm:ss")).orElse(""));
            obj.add(item.getTransAmount());
            obj.add(item.getBillNum());
            obj.add(Optional.ofNullable(item.getTransDateTime()).map(x-> DateFormatUtils.format(x, "yyyy/MM/dd")).orElse(""));
            obj.add(Optional.ofNullable(item.getMatchTime()).map(x-> DateFormatUtils.format(x, "yyyy/MM/dd HH:mm:ss")).orElse(""));
            datalist.add(obj);
        }
        String fileName = "保单存档";
        try {
            EasyExcelUtil.writeExcel(response, datalist, headList, fileName, fileName);
        } catch (IOException e) {
            log.error("{}导出异常：", fileName, e);
            throw new RuntimeException("导出失败：" + e.getMessage());
        }
    }

    /**
     * @Description 删除原始保单文件
     * @Author yangxm
     * @Date 2025/7/2 11:45
     * @param insureDTO
     * @return java.lang.Integer
     */
    @Override
    public int removeOriginalInsureFile(InsureDTO insureDTO) {
        log.info("批量删除原始保单文件，参数：{}", insureDTO);
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (loginUser == null) {
            throw new UtilException("登陆失效，请重新登陆！");
        }
        List<Long> ids;
        if (StringUtils.isNotEmpty(insureDTO.getInsureIdList())) {
            ids = insureDTO.getInsureIdList();
        } else {
            if (StringUtils.isEmpty(insureDTO.getSupplyIdList())) {
                throw new UtilException("参数：供应商简称不能为空");
            }
            ids = insureMapper.selectIdList(insureDTO);
        }
        if (StringUtils.isEmpty(ids)) {
            throw new UtilException("未查询到数据");
        }
        log.info("批量删除原始保单文件，ids：{}", ids);
        //更新原始保单文件
        int row = MybatisBatchUtils.batchUpdateOrInsert(ids, InsureMapper.class, InsureMapper::deleteOriginalInsureFile);
        MatchInsure matchInsure = new MatchInsure();
        matchInsure.setToInsureIdList(ids);
        //根据匹配后查询匹配前的全量数据
        List<Long> fromInsureIdList = matchInsureMapper.selectFullFromInsureIdList(matchInsure);
        //匹配前投保数据处理
        if (StringUtils.isNotEmpty(fromInsureIdList)){
            asyncService.matchInsureHandle(fromInsureIdList, true, false);
        }
        return row;
    }

    /**
     * @Description 批量下载原始保单文件
     * @Author yangxm
     * @Date 2025/7/2 13:47
     * @param insureDTO
     */
    @Override
    public void downloadOriginalInsureFile(InsureDTO insureDTO) {
        log.info("批量下载原始保单文件，参数：{}", insureDTO);
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (loginUser == null){
            throw new IllegalArgumentException("页面超时，请重新登陆");
        }
        //校验供应商简称是否为空
        if (StringUtils.isEmpty(insureDTO.getSupplyIdList()) || insureDTO.getSupplyIdList().size() > 1) {
            throw new IllegalArgumentException("参数：供应商简称不能为空且只能选择一个");
        }
        //根据供应商ID查询供应商简称
        Supply supply = supplyMapper.selectSupplyById(insureDTO.getSupplyIdList().get(0));
        if (supply == null) {
            throw new IllegalArgumentException("供应商信息不存在！");
        }
        String supplyShortName = supply.getSupplyShortName();
        List<Long> ids;
        if (StringUtils.isNotEmpty(insureDTO.getInsureIdList())) {
            ids = insureDTO.getInsureIdList();
        } else {
            ids = insureMapper.selectIdList(insureDTO);
        }
        log.info("批量下载原始保单文件，保单ids:{}, 供应商简称：{}", ids, supplyShortName);
        if (StringUtils.isNotEmpty(ids)){
            //将信息放入mq
            JSONObject message = new JSONObject();
            message.put("userId", loginUser.getId());
            message.put("client", "supply");
            message.put("ids", ids);
            message.put("supplyShortName", supplyShortName);
            message.put("operationType", "original");
            msgSendServer.sendDirectByRoute(RabbitMqConfig.DIRECT_EXCHANGE, RabbitMqConfig.INSURE_FILE_ROUTING_KEY, message.toJSONString(), new CorrelationData(IdUtils.simpleUUID()));
        }
    }

    /**
     * @Description 原始保单批量上传 - 校验文件
     * @Author yangxm
     * @Date 2025/7/2 14:34
     * @param fileNameList
     * @return java.util.Map<java.lang.String,java.util.List<java.lang.String>>
     */
    @Override
    public Map<String, List<String>> checkUploadOriginalInsureFile(List<String> fileNameList) {
        if (StringUtils.isEmpty(fileNameList)) {
            throw new IllegalArgumentException("文件名称列表为空");
        }
        fileNameList = fileNameList.stream().distinct().collect(Collectors.toList());
        //校验结果
        Map<String, List<String>> result = new HashMap<String, List<String>>();
        //查找订单编号存在的集合，返回值为订单编号
        List<String> existentialQxbOrderNos = insureMapper.checkByQxbOrderNoList(fileNameList);
        //假如文件名为保单号，检查保单号是否存在 yangxm  禅道：2485
        List<String> insureNos = insureMapper.checkByInsureNoList(fileNameList);
        if (StringUtils.isEmpty(existentialQxbOrderNos) && (StringUtils.isEmpty(insureNos))) {
            result.put("nonExistent", fileNameList);
            return result;
        }
        List<String> qxbOrderNoSuccessList = new ArrayList<>();
        //查找原始保单文件为null的保单信息，返回值为订单编号
        if (StringUtils.isNotEmpty(existentialQxbOrderNos)){
            qxbOrderNoSuccessList = insureMapper.checkSuccessOriginalInsureFileByQxbOrderNoList(existentialQxbOrderNos);
        }
        List<String> insureNoSuccessList = new ArrayList<>();
        //查找原始保单文件为null的保单信息，返回值为保单号
        if (StringUtils.isNotEmpty(insureNos)) {
            insureNoSuccessList = insureMapper.checkSuccessOriginalInsureFileByInsureNoList(insureNos);
        }
        //返回不存在的订单编号
        List<String> nonExistentList = ListUtils.removeAll(fileNameList, existentialQxbOrderNos);
        //返回不存在的保单号
        List<String> insureNoExistentList = ListUtils.removeAll(nonExistentList, insureNos);
        //返回已存在保单文件的订单号
        List<String> repeatList = ListUtils.removeAll(existentialQxbOrderNos, qxbOrderNoSuccessList);
        //返回已存在保单文件的保单号
        List<String> insureNoRepeatList = ListUtils.removeAll(insureNos, insureNoSuccessList);
        //校验结果
        result.put("nonExistent", insureNoExistentList);
        result.put("success", ListUtils.union(qxbOrderNoSuccessList, insureNoSuccessList));
        result.put("repeat", ListUtils.union(repeatList, insureNoRepeatList));
        return result;
    }

    /**
     * @Description 原始保单批量上传 - 保存文件
     * @Author yangxm
     * @Date 2025/7/2 14:34
     * @param files
     * @return java.lang.String
     */
    @Override
    public String uploadOriginalInsureFiles(MultipartFile[] files) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (loginUser == null) {
            throw new IllegalArgumentException("页面超时，请重新登陆！");
        }
        long begin = System.currentTimeMillis();
        log.info("批量上传原始保单文件开始，数量：{}----------------------", files.length);
        int successNum = 0;
        int failureNum = 0;
        StringBuilder successMsg = new StringBuilder();
        StringBuilder failureMsg = new StringBuilder();
        //每一个任务的list
        List<FutureTask<HashMap<String, Object>>> taskList = new ArrayList<>();

        for (MultipartFile file : files){
            FutureTask<HashMap<String, Object>> task = new FutureTask<>(new UploadOriginalInsureFileJob(file, loginUser.getUsername()));
            threadPoolTaskExecutor.execute(task);
            taskList.add(task);
        }
        for (FutureTask<HashMap<String, Object>> item : taskList) {
            try {
                if (Integer.parseInt(item.get().get("code").toString()) == 500) {
                    failureNum++;
                    failureMsg.append(item.get().get("msg"));
                } else {
                    successNum++;
                    successMsg.append(item.get().get("msg"));
                }
            } catch (InterruptedException | ExecutionException e) {
                log.error("批量上传原始保单文件异常", e);
                throw new UtilException("批量上传原始保单文件失败：" + e.getMessage());
            }
        }
        if (StringUtils.isNotBlank(failureMsg)) {
            failureMsg.insert(0, "很抱歉，上传失败！共 " + failureNum + " 条数据校验未通过，错误如下：");
            throw new RuntimeException(failureMsg.toString());
        } else {
            successMsg.insert(0, "恭喜您，数据已全部上传成功！共 " + successNum + " 条，数据如下：");
        }
        log.info("InsureServiceImpl [uploadInsureFiles] 供应商保单批量上传完成，耗时：{}", (System.currentTimeMillis() - begin));
        return successMsg.toString();
    }

    /**
     * @Description 多线程任务
     * @Author yangxm
     * @Date 2025/7/2 14:42
     */
    class UploadOriginalInsureFileJob implements Callable<HashMap<String, Object>> {

        private final MultipartFile file;

        public UploadOriginalInsureFileJob(MultipartFile file, String username){
            super();
            this.file = file;
        }

        @Override
        public HashMap<String, Object> call() {

            int successNum = 0;
            int failureNum = 0;
            StringBuilder successMsg = new StringBuilder();
            StringBuilder failureMsg = new StringBuilder();

            HashMap<String, Object> map = new HashMap<>();

            String fileName = "";
            try {
                fileName = file.getOriginalFilename();
                if (!fileName.contains(".")) {
                    failureNum++;
                    failureMsg.append("<br/>" + failureNum + "、文件: " + fileName + " 无后缀。");
                    map.put("code", 500);
                    map.put("msg", failureMsg.toString());
                    return map;
                }
                String fileSuffix = fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length());
                fileName = fileName.substring(0, fileName.lastIndexOf("."));
                //校验文件后缀是否是pdf和zip
                if (StringUtils.isBlank(fileSuffix) || (!StringUtils.equals(fileSuffix, "pdf") && !StringUtils.equals(fileSuffix, "zip"))) {
                    failureNum++;
                    failureMsg.append("<br/>" + failureNum + "、文件: " + fileName + " 格式错误，仅可上传pdf文件或zip文件。");
                    map.put("code", 500);
                    map.put("msg", failureMsg.toString());
                    return map;
                }
                //若文件名为订单编号，根据订单编号查询保单信息
                List<Insure> insures = null;
                //若文件名为保单号，根据保单号查询保单信息
                List<Insure> insureList = null;
                //原始保单文件
                insures = insureMapper.selectOriginalInsureByQxbOrderNo(fileName);
                insureList = insureMapper.selectOriginalInsureByInsureNo(fileName);
                boolean flag = (insures == null || insures.isEmpty()) && (insureList == null || insureList.isEmpty());
                if (flag) {
                    failureNum++;
                    failureMsg.append("<br/>" + failureNum + "、文件: " + fileName + " 未找到对应的保单信息。");
                    map.put("code", 500);
                    map.put("msg", failureMsg.toString());
                    return map;
                }
                //订单编号集合
                List<String> qxbOrderNos = new ArrayList<>();
                List<String> notInsureFileQxbOrderNos;
                if (StringUtils.isNotEmpty(insures)) {
                    if (insures.size() > 1) {
                        failureNum++;
                        failureMsg.append("<br/>" + failureNum + "、订单编号: " + fileName + " 对应的保单数异常，请咨询客服。");
                        map.put("code", 500);
                        map.put("msg", failureMsg.toString());
                        return map;
                    }
                    if (StringUtils.isNotBlank(insures.get(0).getOriginalInsureFileUrl())) {
                        failureNum++;
                        failureMsg.append("<br/>" + failureNum + "、订单编号: " + fileName + " 已存在原始保单文件，请先删除原保单文件后再提交。");
                        map.put("code", 500);
                        map.put("msg", failureMsg.toString());
                        return map;
                    }
                    qxbOrderNos.add(insures.get(0).getQxbOrderNo());
                    synchronized (file) {
                        //保存原始保单文件
                        saveOriginalInsureFile(qxbOrderNos, file);
                    }
                    successNum++;
                    successMsg.append("<br/>" + successNum + "、文件: " + fileName + " 上传成功");
                }else if (insureList != null && !insureList.isEmpty()){
                    //获取订单编号集合
                    qxbOrderNos = insureList.stream().map(Insure::getQxbOrderNo).collect(Collectors.toList());
                    //去重
                    qxbOrderNos = qxbOrderNos.stream().distinct().collect(Collectors.toList());
                    //查询保单不存在的订单编号集合
                    notInsureFileQxbOrderNos = insureMapper.selectNotOriginalInsureFileQxbOrderNoList(qxbOrderNos);
                    log.info("保单号：{}, 对应的订单编号：{}, 保单不存在的订单编号：{}", fileName, qxbOrderNos, notInsureFileQxbOrderNos);
                    if (!notInsureFileQxbOrderNos.isEmpty()) {
                        synchronized (file) {
                            //保存原始保单文件
                            saveOriginalInsureFile(qxbOrderNos, file);
                        }
                        successNum++;
                        successMsg.append("<br/>" + successNum + "、文件: " + fileName + " 上传成功");
                    }
                }
            } catch (Exception e) {
                failureNum++;
                String msg = "<br/>" + failureNum + "、文件： " + fileName + " 上传失败：";
                failureMsg.append(msg + e.getMessage());
                log.error("多线程上传保单文件：" + msg, e);
            }
            if (failureNum > 0) {
                map.put("code", 500);
                map.put("msg", failureMsg.toString());
                return map;
            } else {
                map.put("code", 200);
                map.put("msg", successMsg.toString());
                return map;
            }
        }

    }

    /**
     * @Description 原始文件保存
     * @Author yangxm
     * @Date 2025/7/2 14:52
     * @param qxbOrderNos
     * @param multipartFile
     */
    private void saveOriginalInsureFile(List<String> qxbOrderNos, MultipartFile multipartFile) {
        //保存到oss
        String url = "";
        try {
            //保存到OSS
            FileInfo fileInfo = fileInfoService.saveByOss(multipartFile, IdUtils.fastSimpleUUID(), true);
            url = fileInfo.getUrl();
        } catch (Exception e) {
            log.error("原始文件保存，文件上传oss异常：", e);
            throw new RuntimeException("原始文件保存，文件上传oss异常：" + e.getMessage());
        }
        //更新保单信息
        Insure insure = new Insure();
        insure.setOriginalInsureFileUrl(url);
        insure.setQxbOrderNoList(qxbOrderNos);
        insureMapper.updateOriginalInsureFileByOrderNoList(insure);
    }


    /**
     * @Description 多线程任务处理凭证上传，文件名称为订单编号
     * @Author yangxm
     * @Date 2025/6/20 10:02
     */
    class SaveCustomerInsDecFileUploadJob implements Callable<HashMap<String, Object>> {
        private MultipartFile file;
        private String createBy;

        public SaveCustomerInsDecFileUploadJob (MultipartFile file, String createBy){
            super();
            this.file = file;
            this.createBy = createBy;
        }

        @Override
        public HashMap<String, Object> call() {
            int successNum = 0;
            int failureNum = 0;
            StringBuilder successMsg = new StringBuilder();
            StringBuilder failureMsg = new StringBuilder();

            HashMap<String, Object> map = new HashMap<>();
            String fileName = "";
            TransactionStatus status = null;
            try {
                fileName = file.getOriginalFilename();
                if (StringUtils.isBlank(fileName) || !fileName.contains(".")) {
                    failureNum++;
                    failureMsg.append("<br/>").append(failureNum).append("、文件: ").append(fileName).append(" 名称错误或无后缀。");
                    map.put("code", 500);
                    map.put("msg", failureMsg.toString());
                    return map;
                }
                fileName = fileName.substring(0, fileName.lastIndexOf("."));
                //根据文件名查询保单信息
                Insure insure = insureMapper.selectInsureByQxbOrderNo(fileName);
                if (insure == null){
                    failureNum++;
                    failureMsg.append("<br/>").append(failureNum).append("、文件: ").append(fileName).append(" 未找到保单信息。");
                    map.put("code", 500);
                    map.put("msg", failureMsg.toString());
                    return map;
                }
                //查看凭证文件是否已经存在
                if (StringUtils.isNotBlank(insure.getCustomerInsDec())){
                    failureNum++;
                    failureMsg.append("<br/>").append(failureNum).append("、文件: ").append(fileName).append(" 已存在凭证。");
                    map.put("code", 500);
                    map.put("msg", failureMsg.toString());
                    return map;
                }
                //开启事务：手动提交/回滚事务
                status = transactionManager.getTransaction(transactionDefinition);
                //文件基础路径
                String basePath = SupplyConfig.getProfile() + "/" + FileUtils.getPath() + IdUtils.fastSimpleUUID();
                //加水印后的文件全路径
                String waterMarkPath = basePath + "/waterMark/" + file.getOriginalFilename();
                //另存为图片pdf的文件路径
                String imgPdfPath = basePath + "/imgPdf/" + file.getOriginalFilename();
                //添加水印
                PdfWaterUtils.addWaterMark(file.getInputStream(), waterMarkPath, null, null);
                //另存为图像pdf
                PdfWaterUtils.saveAsImgPdf(waterMarkPath, imgPdfPath);
                //转成MultipartFile
                file = new MockMultipartFile("file", file.getOriginalFilename(), "text/plain", Files.newInputStream(Paths.get(imgPdfPath)));
                //保存到OSS
                FileInfo fileInfo = fileInfoService.saveByOss(file, IdUtils.fastSimpleUUID(), true);
                //更新凭证
                insureMapper.updateInsureCustomerInsDec(insure.getId(), fileInfo.getOwner());
                //保存凭证上传记录
                InsureLog insureLog = new InsureLog();
                insureLog.setInsureId(insure.getId());
                insureLog.setClient("2");
                insureLog.setOperateType("5");
                insureLog.setContent("凭证上传");
                insureLog.setFileUrlAfter(fileInfo.getUrl());
                insureLog.setCreateBy(createBy);
                insureLogMapper.insertInsureLog(insureLog);

                successNum++;
                successMsg.append("<br/>").append(successNum).append("、文件: ").append(fileName).append(" 上传成功");
                // 提交事务
                transactionManager.commit(status);
            } catch (Exception e) {
                failureNum++;
                String msg = "<br/>" + failureNum + "、文件： " + fileName + " 上传失败：";
                failureMsg.append(msg).append(e.getMessage());
                log.error("多线程上传凭证文件：" + msg, e);
                // 回滚事务
                if (status != null) {
                    transactionManager.rollback(status);
                }
            }
            if (failureNum > 0) {
                map.put("code", 500);
                map.put("msg", failureMsg.toString());
                return map;
            } else {
                map.put("code", 200);
                map.put("msg", successMsg.toString());
                return map;
            }
        }
    }

    /**
     * @Description 多线程任务处理保存供应商保单上传日志
     * @Author yangxm
     * @Date 2025/6/16 17:05
     */
    class SaveSupplyInsureFileUploadLogJob implements Callable<HashMap<String, Object>> {

        private MultipartFile file;
        private String createBy;

        public SaveSupplyInsureFileUploadLogJob (MultipartFile file, String createBy){
            super();
            this.file = file;
            this.createBy = createBy;
        }
        @Override
        public HashMap<String, Object> call() {

            int successNum = 0;
            int failureNum = 0;
            StringBuilder successMsg = new StringBuilder();
            StringBuilder failureMsg = new StringBuilder();

            HashMap<String, Object> map = new HashMap<>();

            String fileName = "";
            String fileUrl;
            Long id = null;
            SupplyInsureFileUploadLog supplyInsureFileUploadLog = null;
            try {
                fileName = file.getOriginalFilename();
                if (fileName != null && !fileName.contains(".")) {
                    failureNum++;
                    failureMsg.append("<br/>").append(failureNum).append("、文件: ").append(fileName).append(" 无后缀。");
                    map.put("code", 500);
                    map.put("msg", failureMsg.toString());
                    return map;
                }
                String fileSuffix = fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length());
                fileName = fileName.substring(0, fileName.lastIndexOf("."));
                //校验文件后缀是否是pdf和zip
                if (StringUtils.isBlank(fileSuffix) || (!StringUtils.equals(fileSuffix, "pdf") && !StringUtils.equals(fileSuffix, "zip"))) {
                    failureNum++;
                    failureMsg.append("<br/>").append(failureNum).append("、文件: ").append(fileName).append(" 格式错误，仅可上传pdf文件或zip文件。");
                    map.put("code", 500);
                    map.put("msg", failureMsg.toString());
                    return map;
                }
                fileUrl = fileInfoService.save(file);
                supplyInsureFileUploadLog = new SupplyInsureFileUploadLog();
                supplyInsureFileUploadLog.setFileName(fileName);
                supplyInsureFileUploadLog.setInsureFileUrl(fileUrl);
                supplyInsureFileUploadLog.setCreateBy(createBy);
                supplyInsureFileUploadLogMapper.insert(supplyInsureFileUploadLog);
                id = supplyInsureFileUploadLog.getId();
                if (id == null){
                    failureNum++;
                    failureMsg.append("<br/>").append(failureNum).append("、文件: ").append(fileName).append(" 保存失败！");
                    map.put("code", 500);
                    map.put("msg", failureMsg.toString());
                    return map;
                }
                successNum++;
                successMsg.append("<br/>").append(successNum).append("、文件: ").append(fileName).append(" 上传成功");
            } catch (Exception e) {
                failureNum++;
                String msg = "<br/>" + failureNum + "、文件： " + fileName + " 上传失败：";
                failureMsg.append(msg + e.getMessage());
                log.error("多线程上传保单文件：" + msg, e);
            }
            if (failureNum > 0) {
                map.put("code", 500);
                map.put("msg", failureMsg.toString());
                return map;
            } else {
                map.put("code", 200);
                map.put("msg", successMsg.toString());
                map.put("id", id);
                return map;
            }
        }
    }

    /**
     * @param list
     * @return void
     * @Description 字典值处理
     * @Author yangxm
     * @Date 2025/6/16 17:05
     */
    private void dictHandle(List<Insure> list) {
        if (StringUtils.isNotEmpty(list)) {
            List<Dict> dictList = dictMapper.selectDictList();
            Map<String, Map<String, String>> dictMap = new ConcurrentHashMap<>();
            if (StringUtils.isNotEmpty(dictList)) {
                dictMap = dictList.stream()
                        .filter(c -> c.getVal() != null)
                        .collect(Collectors.groupingBy(Dict::getType, Collectors.toMap(Dict::getK, Dict::getVal)));
            }

            Map<String, String> mealNameMap = dictMap.getOrDefault("mealname", Collections.emptyMap());
            Map<String, String> maimRatioMap = dictMap.getOrDefault("maimRatio", Collections.emptyMap());
            Map<String, String> insureperiodMap = dictMap.getOrDefault("insureperiod", Collections.emptyMap());
            Map<String, String> insuretypeMap = dictMap.getOrDefault("insuretype", Collections.emptyMap());
            Map<String, String> jobtypeMap = dictMap.getOrDefault("jobtype", Collections.emptyMap());
            Map<String, String> extensionMap = dictMap.getOrDefault("extension", Collections.emptyMap());
            Map<String, String> uploadInsureFileStates = dictMap.getOrDefault("insureFileStatus", Collections.emptyMap());
            Map<String, String> suddenDeathRatioMap = dictMap.getOrDefault("suddenDeathRatio", Collections.emptyMap());
            Map<String, String> guardSuddenMap = dictMap.getOrDefault("guardSudden", Collections.emptyMap());
            Map<String, String> matchTypeMap = dictMap.getOrDefault("matchType", Collections.emptyMap());
            Map<String, String> deptMap = dictMap.getOrDefault("dept", Collections.emptyMap());
            //供应商
            List<Supply> supplyList = supplyMapper.selectSupplyList();
            Map<Long, Supply> supplyMap = supplyList.stream()
                    .collect(Collectors.toMap(Supply::getId, s -> s));
            //账号信息
            Map<Long, String> usernameMap = slaveUserMapper.selectUsernameList().stream()
                    .collect(Collectors.toMap(SlaveUser::getId, SlaveUser::getUsername));
            //签约公司
            Map<Long, String> signCompanyNameMap = signCompanyMapper.selectSignCompanyNameList().stream()
                    .collect(Collectors.toMap(SignCompany::getId, SignCompany::getCompanyName));

            // 雇主投保ID列表
            List<Long> employInsureIdList = list.stream()
                    .filter(x -> !StringUtils.equals("6", x.getInsurePeriod()))
                    .map(Insure::getId)
                    .collect(Collectors.toList());

            Map<Long, Insure> employMatchInsureMap = Collections.emptyMap();
            if (!employInsureIdList.isEmpty()) {
                List<Insure> employMatchInsureList = insureMapper.matchInsureList(employInsureIdList);
                employMatchInsureMap = employMatchInsureList.stream().collect(Collectors.toMap(Insure::getId, x -> x));
            }

            // 天保方案ID列表
            Set<Long> schemeIdSet = list.stream()
                    .filter(x -> StringUtils.equals("6", x.getInsurePeriod()))
                    .map(Insure::getCustomerMealId)
                    .collect(Collectors.toSet());

            Map<Long, SchemeInsure> daySchemeInsureMap = Collections.emptyMap();
            if (!schemeIdSet.isEmpty()) {
                List<SchemeInsure> daySchemeInsureList = schemeInsureMapper.selectSchemeInsuresBySchemeIds(schemeIdSet);
                daySchemeInsureMap = daySchemeInsureList.stream().collect(Collectors.toMap(SchemeInsure::getSchemeId, x -> x));
            }
            String matchType;
            Insure insure;
            // 投保周期
            String insurePeriod = "";
            Long insureId;
            Insure employMatchInsure;
            Long schemeId;
            SchemeInsure schemeInsure;
            String toSupplyIds;

            for (int i = 0; i < list.size(); i++) {
                insure = list.get(i);
                insureId = insure.getId();
                schemeId = insure.getCustomerMealId();
                insurePeriod = insure.getInsurePeriod();
                insure.setBelongCompanyName(deptMap.getOrDefault(String.valueOf(insure.getBelongCompanyId()), ""));
                insure.setPayCompanyName((StringUtils.equals("0", insure.getInsureType()) || StringUtils.equals("1", insure.getInsureType()))
                        ? insure.getCustomerName() : signCompanyNameMap.getOrDefault(insure.getPayCompanyId(), ""));
                insure.setMealNameVal(mealNameMap.get(insure.getMealName()));
                insure.setMaimRatioVal(maimRatioMap.get(insure.getMaimRatio()));
                insure.setInsurePeriodVal(insureperiodMap.get(insurePeriod));
                insure.setInsureTypeVal(insuretypeMap.get(insure.getInsureType()));
                insure.setJobTypeVal(jobtypeMap.get(insure.getJobType()));
                insure.setExtensionVal(extensionMap.get(insure.getExtension()));
                insure.setSuddenDeathRatioVal(suddenDeathRatioMap.get(insure.getSuddenDeathRatio()));
                insure.setGuardSuddenVal(guardSuddenMap.get(insure.getGuardSudden()));
                insure.setServiceName(usernameMap.getOrDefault(insure.getServiceId(), ""));
                if (!StringUtils.equals("6", insurePeriod)) {
                    employMatchInsure = employMatchInsureMap.get(insureId);
                    if (Objects.nonNull(employMatchInsure)) {
                        matchType = employMatchInsure.getMatchType();
                        if (StringUtils.isNotBlank(matchType)) {
                            List<String> matchTypeList = new ArrayList<>();
                            String[] matchTypeArr = matchType.split(",");
                            Arrays.asList(matchTypeArr).forEach(item -> matchTypeList.add(matchTypeMap.get(item)));
                            insure.setMatchTypeVal(String.join("、", matchTypeList));
                        }
                        insure.setMatchTime(employMatchInsure.getMatchTime());
                        insure.setToSupplyShortName(employMatchInsure.getToSupplyShortName());
                    }
                }

                if (StringUtils.equals("6", insurePeriod)) {
                    schemeInsure = daySchemeInsureMap.get(schemeId);
                    if (Objects.nonNull(schemeInsure)) {
                        matchType = schemeInsure.getMatchTypes();
                        if (StringUtils.isNotBlank(matchType)) {
                            List<String> matchTypeList = new ArrayList<>();
                            String[] matchTypeArr = matchType.split(",");
                            Arrays.asList(matchTypeArr).forEach(item -> matchTypeList.add(matchTypeMap.get(item)));
                            insure.setMatchTypeVal(String.join("、", matchTypeList));
                        }
                        insure.setMatchTime(schemeInsure.getUpdateTime());
                        toSupplyIds = schemeInsure.getToSupplyIds();
                        if (StringUtils.isNotBlank(toSupplyIds)) {
                            List<String> toSupplyShortNameList = new ArrayList<>();
                            String[] toSupplyIdsArr = toSupplyIds.split(",");
                            Arrays.asList(toSupplyIdsArr).forEach(item -> toSupplyShortNameList.add(supplyMap.get(Long.parseLong(item)).getSupplyShortName()));
                            insure.setToSupplyShortName(String.join("、", toSupplyShortNameList));
                        }
                    }
                }
                insure.setInsureNoStatus(StringUtils.isNotBlank(insure.getInsureNo()) ? "已上传" : "待上传");
                //判断保单文件是否上传
                if (StringUtils.isNotBlank(insure.getInsureFile())) {
                    insure.setInsureFileStatus(uploadInsureFileStates.get("2"));
                } else {
                    insure.setInsureFileStatus(uploadInsureFileStates.get("1"));
                }
                //判断保单凭证是否上传
                if (StringUtils.isNotBlank(insure.getCustomerInsDec())) {
                    insure.setCustomerInsDecStatus(uploadInsureFileStates.get("2"));
                } else {
                    insure.setCustomerInsDecStatus(uploadInsureFileStates.get("1"));
                }
                if ("1".equals(insure.getTemplateDownloadFlag())) {
                    insure.setTemplateDownloadFlag("已下载");
                } else {
                    insure.setTemplateDownloadFlag("未下载");
                }
                //原保单文件
                if (StringUtils.isNotBlank(insure.getOriginalInsureFileUrl())){
                    insure.setOriginalInsureFileStatus(uploadInsureFileStates.get("2"));
                }else {
                    insure.setOriginalInsureFileStatus(uploadInsureFileStates.get("1"));
                }
                insure.setFinanceReckonVal("0".equals(insure.getFinanceReckon()) ? "否" : "是");
            }
        }
    }

}
